<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Babylon.js 贝塞尔曲线渲染</title>
    <!-- 引入Babylon.js -->
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
    <!-- 添加材质库 -->
    <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <style>
        body, html {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            background-color: #111;
        }
        #renderCanvas {
            width: 100%;
            height: 100%;
            touch-action: none;
        }
        .controls {
            position: absolute;
            top: 10px;
            left: 10px;
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 10px;
            border-radius: 5px;
            z-index: 100;
        }
        button {
            margin: 5px;
            padding: 5px 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<div class="controls">
    <button onclick="togglePoints()">显示/隐藏控制点</button>
    <button onclick="toggleTangents()">显示/隐藏切线</button>
    <button onclick="toggleCurve()">显示/隐藏曲线</button>
</div>

<script>
    // 确保所有库加载完成后再执行代码
    window.addEventListener('DOMContentLoaded', function() {
        // 您的样条数据
        const splineData = {
            "name": "样条",
            "type": "Spline",
            "point_count": 3,
            "is_closed": false,
            "interpolation_type": 4,
            "points": [
                {
                    "index": 0,
                    "position": {
                        "x": -259.11504424778764,
                        "y": 89.20353982300885,
                        "z": 0.0
                    },
                    "tangent_left": {
                        "x": 39.76695742204417,
                        "y": 145.81217721416192,
                        "z": 5.048709793414476e-29
                    },
                    "tangent_right": {
                        "x": -40.77876106194691,
                        "y": -149.52212389380534,
                        "z": 0.0
                    }
                },
                {
                    "index": 1,
                    "position": {
                        "x": 335.57522123893807,
                        "y": -19.53982300884956,
                        "z": 0.0
                    },
                    "tangent_left": {
                        "x": -42.92655108565768,
                        "y": 42.131614954441794,
                        "z": 5.048709793414476e-29
                    },
                    "tangent_right": {
                        "x": 91.75221238938052,
                        "y": -90.05309734513273,
                        "z": 0.0
                    }
                },
                {
                    "index": 2,
                    "position": {
                        "x": 496.99115044247793,
                        "y": 158.86725663716814,
                        "z": 0.0
                    },
                    "tangent_left": {
                        "x": -23.78761061946904,
                        "y": -47.57522123893807,
                        "z": 0.0
                    },
                    "tangent_right": {
                        "x": 21.20322661431916,
                        "y": 42.40645322863832,
                        "z": 0.0
                    }
                }
            ],
            "segments": [
                {
                    "start": 0,
                    "count": 3
                }
            ]
        };

        // 创建场景
        const canvas = document.getElementById("renderCanvas");
        const engine = new BABYLON.Engine(canvas, true);

        // 状态变量
        let showPoints = true;
        let showTangents = true;
        let showCurve = true;

        // 存储创建的对象
        let controlPoints = [];
        let tangentLines = [];
        let curveMesh = null;
        let scene = null; // 预定义scene变量

        function createScene() {
            scene = new BABYLON.Scene(engine);

            // 创建相机
            const camera = new BABYLON.ArcRotateCamera("camera", Math.PI / 2, Math.PI / 4, 1000, new BABYLON.Vector3(100, 0, 0), scene);
            camera.attachControl(canvas, true);

            // 创建光源
            const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
            light.intensity = 0.7;

            // 创建网格平面作为参考
            const grid = BABYLON.MeshBuilder.CreateGround("ground", {width: 2000, height: 2000}, scene);

            // 使用标准材质替代GridMaterial
            const gridMaterial = new BABYLON.StandardMaterial("gridMaterial", scene);
            gridMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.2, 0.2);
            gridMaterial.wireframe = true; // 使用线框模式模拟网格
            grid.material = gridMaterial;

            // 渲染样条曲线
            renderSpline(scene);

            return scene;
        }

        function renderSpline(scene) {
            // 清除旧对象
            if (controlPoints) controlPoints.forEach(point => point.dispose());
            if (tangentLines) tangentLines.forEach(line => line.dispose());
            if (curveMesh) curveMesh.dispose();

            controlPoints = [];
            tangentLines = [];

            // 渲染控制点
            if (showPoints) {
                splineData.points.forEach(point => {
                    const sphere = BABYLON.MeshBuilder.CreateSphere("point", {diameter: 10}, scene);
                    sphere.position = new BABYLON.Vector3(
                        point.position.x,
                        point.position.y,
                        point.position.z
                    );

                    // 为不同点设置不同颜色
                    const material = new BABYLON.StandardMaterial("pointMat", scene);
                    if (point.index === 0) material.diffuseColor = new BABYLON.Color3(1, 0, 0); // 起点红色
                    else if (point.index === splineData.points.length - 1) material.diffuseColor = new BABYLON.Color3(0, 1, 0); // 终点绿色
                    else material.diffuseColor = new BABYLON.Color3(0, 0, 1); // 中间点蓝色

                    sphere.material = material;
                    controlPoints.push(sphere);
                });
            }

            // 渲染切线
            if (showTangents) {
                splineData.points.forEach(point => {
                    // 左切线
                    if (point.tangent_left && (point.tangent_left.x !== 0 || point.tangent_left.y !== 0 || point.tangent_left.z !== 0)) {
                        const start = new BABYLON.Vector3(
                            point.position.x,
                            point.position.y,
                            point.position.z
                        );

                        const end = new BABYLON.Vector3(
                            point.position.x + point.tangent_left.x,
                            point.position.y + point.tangent_left.y,
                            point.position.z + point.tangent_left.z
                        );

                        const leftTangent = BABYLON.MeshBuilder.CreateLines("leftTangent", {
                            points: [start, end],
                            updatable: false,
                            colors: [
                                new BABYLON.Color4(1, 1, 0, 1), // 黄色
                                new BABYLON.Color4(1, 1, 0, 1)
                            ]
                        }, scene);

                        tangentLines.push(leftTangent);
                    }

                    // 右切线
                    if (point.tangent_right && (point.tangent_right.x !== 0 || point.tangent_right.y !== 0 || point.tangent_right.z !== 0)) {
                        const start = new BABYLON.Vector3(
                            point.position.x,
                            point.position.y,
                            point.position.z
                        );

                        const end = new BABYLON.Vector3(
                            point.position.x + point.tangent_right.x,
                            point.position.y + point.tangent_right.y,
                            point.position.z + point.tangent_right.z
                        );

                        const rightTangent = BABYLON.MeshBuilder.CreateLines("rightTangent", {
                            points: [start, end],
                            updatable: false,
                            colors: [
                                new BABYLON.Color4(0, 1, 1, 1), // 青色
                                new BABYLON.Color4(0, 1, 1, 1)
                            ]
                        }, scene);

                        tangentLines.push(rightTangent);
                    }
                });
            }

            // 渲染曲线
            if (showCurve) {
                // 创建曲线点
                const curvePoints = [];
                const segments = splineData.segments || [{start: 0, count: splineData.points.length}];

                segments.forEach(segment => {
                    const start = segment.start;
                    const count = segment.count;

                    // 至少需要3个点才能形成贝塞尔曲线
                    if (count < 3) return;

                    // 为每个分段创建曲线
                    for (let i = start; i < start + count - 1; i++) {
                        if (i + 1 >= splineData.points.length) break;

                        const p0 = new BABYLON.Vector3(
                            splineData.points[i].position.x,
                            splineData.points[i].position.y,
                            splineData.points[i].position.z
                        );

                        const p1 = new BABYLON.Vector3(
                            splineData.points[i].position.x + splineData.points[i].tangent_right.x,
                            splineData.points[i].position.y + splineData.points[i].tangent_right.y,
                            splineData.points[i].position.z + splineData.points[i].tangent_right.z
                        );

                        const p2 = new BABYLON.Vector3(
                            splineData.points[i+1].position.x + splineData.points[i+1].tangent_left.x,
                            splineData.points[i+1].position.y + splineData.points[i+1].tangent_left.y,
                            splineData.points[i+1].position.z + splineData.points[i+1].tangent_left.z
                        );

                        const p3 = new BABYLON.Vector3(
                            splineData.points[i+1].position.x,
                            splineData.points[i+1].position.y,
                            splineData.points[i+1].position.z
                        );

                        // 使用4阶贝塞尔曲线计算点
                        const numPoints = 20; // 每段曲线的点数
                        for (let j = 0; j <= numPoints; j++) {
                            const t = j / numPoints;
                            const point = bezierPoint(p0, p1, p2, p3, t);
                            curvePoints.push(point);
                        }
                    }
                });

                // 创建曲线网格
                if (curvePoints.length > 1) {
                    curveMesh = BABYLON.MeshBuilder.CreateLines("curve", {
                        points: curvePoints,
                        updatable: false,
                        colors: Array(curvePoints.length).fill(new BABYLON.Color4(1, 1, 1, 1))
                    }, scene);
                }
            }
        }

        // 计算贝塞尔曲线上的点
        function bezierPoint(p0, p1, p2, p3, t) {
            const u = 1 - t;
            const tt = t * t;
            const uu = u * u;
            const uuu = uu * u;
            const ttt = tt * t;

            // 贝塞尔公式: B(t) = u³P₀ + 3u²tP₁ + 3ut²P₂ + t³P₃
            const x = uuu * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + ttt * p3.x;
            const y = uuu * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + ttt * p3.y;
            const z = uuu * p0.z + 3 * uu * t * p1.z + 3 * u * tt * p2.z + ttt * p3.z;

            return new BABYLON.Vector3(x, y, z);
        }

        // 控制函数
        function togglePoints() {
            showPoints = !showPoints;
            renderSpline(scene);
        }

        function toggleTangents() {
            showTangents = !showTangents;
            renderSpline(scene);
        }

        function toggleCurve() {
            showCurve = !showCurve;
            renderSpline(scene);
        }

        // 创建场景
        scene = createScene();

        // 运行渲染循环
        engine.runRenderLoop(() => {
            if (scene) scene.render();
        });

        // 处理窗口大小变化
        window.addEventListener("resize", () => {
            engine.resize();
        });
    });
</script>
</body>
</html>